In this notebook we will cover an approach to do an exploratory data analysis with the data of the Brazilian general elections of 2018.

1. Obtaining the data

We will fetch the data from the oficial governemnt repository available at the webpage of the TSE (Tribunal Superior Eleitoral.)

1.1 Importing libraries

require(rvest)     # web scrapping
require(plotly)    # data visualization
require(ggplot2)   # data visualization
require(lubridate) # format dates 
require(tidyverse) # data cleansing

1.2 Set working directory

a) Variables

wd       <- '~/dev/r' # '/cloud/project'
project  <- 'brz_elections'
raw_data <- 'raw_data'

b) First level path

dest_path <- file.path(wd, project)

if (!dir.exists(dest_path)) {
  dir.create(dest_path)   # create path case it does not exist
  print(paste("Folder", dest_path , "created at", wd))
} else {
  print(paste("Folder", dest_path , "already exists"))
}
[1] "Folder ~/dev/r/brz_elections already exists"

c) Second level path

dest_path <- file.path(dest_path, raw_data)

if (!dir.exists(dest_path)) {
  dir.create(dest_path) # create directory
  print(paste("Folder ", dest_path , "created sucessfully "))
} else {
  print(paste("Folder ", dest_path , "already exists"))
}
[1] "Folder  ~/dev/r/brz_elections/raw_data already exists"

d) Set working directory

setwd(dest_path)
The working directory was changed to /home/gaston/dev/r/brz_elections inside a notebook chunk. The working directory will be reset when the chunk is finished running. Use the knitr root.dir option in the setup chunk to change the working directory for notebook chunks.

1.3 Dowload source files

a) Variables

# main page with the source data
target_url <- "http://www.tse.jus.br/hotsites/pesquisas-eleitorais/prestacao_contas_anos/2018.html"

# get html from source URL above
html       <-  read_html(target_url)

# use css selector to just filter the path with the other url adresses
nodes      <-  html_nodes(html, 'div p a')

# final fetch of the url addresses with the raw data
zip_url    <-  html_attr(nodes, 'href')

b) Download files

# now need to do a for loop in this case
# r handles the download of the whole vector
# *** WARNING ***
# some files are huge - >= 200 MB
download.file(url = zip_url, 
              destfile = file.path(dest_path, basename(zip_url)),
              mode = 'wb')
trying URL 'http://agencia.tse.jus.br/estatistica/sead/odsele/prestacao_contas/prestacao_de_contas_eleitorais_orgaos_partidarios_2018.zip'
trying URL 'http://agencia.tse.jus.br/estatistica/sead/odsele/prestacao_contas/prestacao_de_contas_eleitorais_candidatos_2018.zip'
trying URL 'http://agencia.tse.jus.br/estatistica/sead/odsele/prestacao_contas/CNPJ_campanha_2018.zip'

c) Unziping


for (f in file.path(dest_path, basename(zip_url))) {
  print(f)
  unzip(f, exdir = dest_path)
}
[1] "~/dev/r/brz_elections/raw_data/prestacao_de_contas_eleitorais_orgaos_partidarios_2018.zip"
error 1 in extracting from zip file
[1] "~/dev/r/brz_elections/raw_data/prestacao_de_contas_eleitorais_candidatos_2018.zip"
[1] "~/dev/r/brz_elections/raw_data/CNPJ_campanha_2018.zip"
error 1 in extracting from zip file

d) Delete some files

# delete redundant files that will not be used
pattern         <- '*BRASIL*'
files_to_remove <- grep(dir(dest_path), pattern = pattern, inv=T, value = T)
file.remove(file.path(dest_path,files_to_remove))
cannot remove file '~/dev/r/brz_elections/raw_data/a', reason 'Directory not empty'
 [1] FALSE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE
[20]  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE

2. Loading and cleaning the data

2.1 Load and clean downloaded csvs

a) Revenues

b) Expenses paid

c) Expenses hired

despesa_c <-  read.csv(file.path(dest_path, 'despesas_contratadas_candidatos_2018_BRASIL.csv'),
                    sep = ';', 
                    dec = ',',
                    encoding = 'latin1')

rm_columns <- c('NR_CPF_VICE_CANDIDATO','SG_UF','CD_ELEICAO','DS_ELEICAO',
                'CD_TIPO_ELEICAO','NM_TIPO_ELEICAO','ANO_ELEICAO','DT_GERACAO',
                'HH_GERACAO','TP_PRESTACAO_CONTAS','SQ_PRESTADOR_CONTAS','NR_CPF_CANDIDATO',
                'NM_PARTIDO','NR_PARTIDO','DS_CNAE_FORNECEDOR','CD_TIPO_FORNECEDOR','CD_CNAE_FORNECEDOR',
                'DS_ESFERA_PART_FORNECEDOR','CD_ESFERA_PART_FORNECEDOR','SG_UF_FORNECEDOR',
                'CD_MUNICIPIO_FORNECEDOR','NM_MUNICIPIO_FORNECEDOR','SQ_CANDIDATO_FORNECEDOR',
                'NR_CANDIDATO_FORNECEDOR','CD_CARGO_FORNECEDOR','DS_ORIGEM_DESPESA',
                'CD_ORIGEM_DESPESA','SQ_PARCELAMENTO_DESPESA')

despesa_c[, rm_columns] <-NULL

d) Backup clean frames

saveRDS(receita,   file.path(dest_path, 'clean_revenue.rds'))
saveRDS(despesa,   file.path(dest_path, 'clean_expenses_paid.rds'))
saveRDS(despesa_c, file.path(dest_path, 'clean_expenses_hired.rds'))

2.2 Download candidate’s assets data

a) Download

b) Clean

c) Backup

LS0tCnRpdGxlOiAiKkJyYXppbGlhbiAyMDE4IEVsZWN0aW9ucyBFREEqIgojIGF1dGhvcjogIkdhc3RvbiBHdWlsbGF1eCIKIyBkYXRlOiAiMjAyMC0wMS0yNiIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKSW4gdGhpcyBub3RlYm9vayB3ZSB3aWxsIGNvdmVyIGFuIGFwcHJvYWNoIHRvIGRvIGFuIGV4cGxvcmF0b3J5IGRhdGEgYW5hbHlzaXMgd2l0aCB0aGUgZGF0YSBvZiB0aGUgQnJhemlsaWFuIGdlbmVyYWwgZWxlY3Rpb25zIG9mIDIwMTguCgojIyAqKjEuIE9idGFpbmluZyB0aGUgZGF0YSoqCldlIHdpbGwgZmV0Y2ggdGhlIGRhdGEgZnJvbSB0aGUgb2ZpY2lhbCBnb3Zlcm5lbW50IHJlcG9zaXRvcnkgYXZhaWxhYmxlIGF0IHRoZSB3ZWJwYWdlIG9mIHRoZSBUU0UgKFRyaWJ1bmFsIFN1cGVyaW9yIEVsZWl0b3JhbC4pCgoqICoqTWFpbiBVUkwqKiAtIGh0dHA6Ly93d3cudHNlLmp1cy5ici9lbGVpY29lcy9lc3RhdGlzdGljYXMvcmVwb3NpdG9yaW8tZGUtZGFkb3MtZWxlaXRvcmFpcy0xL3JlcG9zaXRvcmlvLWRlLWRhZG9zLWVsZWl0b3JhaXMKKiAqKk1haW4gZnJhbWUgZnJvbSBhYm92ZSBVUkwqKiAtIGh0dHA6Ly93d3cudHNlLmp1cy5ici9ob3RzaXRlcy9wZXNxdWlzYXMtZWxlaXRvcmFpcy9pbmRleC5odG1sCiogKipUYWIgd2l0aCB0aGUgYWNjb3VudGFiaWxpdHkgZGF0YSoqIC0gaHR0cDovL3d3dy50c2UuanVzLmJyL2hvdHNpdGVzL3Blc3F1aXNhcy1lbGVpdG9yYWlzL3ByZXN0YWNhb19jb250YXMuaHRtbAoqICoqRmluYWwgbGluayB3aXRoIHRoZSAyMDE4IGRhdGEqKiAtIGh0dHA6Ly93d3cudHNlLmp1cy5ici9ob3RzaXRlcy9wZXNxdWlzYXMtZWxlaXRvcmFpcy9wcmVzdGFjYW9fY29udGFzX2Fub3MvMjAxOC5odG1sCgojIyMgMS4xIEltcG9ydGluZyBsaWJyYXJpZXMKYGBge3J9CnJlcXVpcmUocnZlc3QpICAgICAjIHdlYiBzY3JhcHBpbmcKcmVxdWlyZShwbG90bHkpICAgICMgZGF0YSB2aXN1YWxpemF0aW9uCnJlcXVpcmUoZ2dwbG90MikgICAjIGRhdGEgdmlzdWFsaXphdGlvbgpyZXF1aXJlKGx1YnJpZGF0ZSkgIyBmb3JtYXQgZGF0ZXMgCnJlcXVpcmUodGlkeXZlcnNlKSAjIGRhdGEgY2xlYW5zaW5nCmBgYAoKIyMjIDEuMiBTZXQgd29ya2luZyBkaXJlY3Rvcnkgey50YWJzZXR9CiMjIyMgKiphKSBWYXJpYWJsZXMqKgpgYGB7cn0Kd2QgICAgICAgPC0gJ34vZGV2L3InICMgJy9jbG91ZC9wcm9qZWN0Jwpwcm9qZWN0ICA8LSAnYnJ6X2VsZWN0aW9ucycKcmF3X2RhdGEgPC0gJ3Jhd19kYXRhJwpgYGAKCiMjIyMgKipiKSBGaXJzdCBsZXZlbCBwYXRoKioKYGBge3J9CmRlc3RfcGF0aCA8LSBmaWxlLnBhdGgod2QsIHByb2plY3QpCgppZiAoIWRpci5leGlzdHMoZGVzdF9wYXRoKSkgewogIGRpci5jcmVhdGUoZGVzdF9wYXRoKSAgICMgY3JlYXRlIHBhdGggY2FzZSBpdCBkb2VzIG5vdCBleGlzdAogIHByaW50KHBhc3RlKCJGb2xkZXIiLCBkZXN0X3BhdGggLCAiY3JlYXRlZCBhdCIsIHdkKSkKfSBlbHNlIHsKICBwcmludChwYXN0ZSgiRm9sZGVyIiwgZGVzdF9wYXRoICwgImFscmVhZHkgZXhpc3RzIikpCn0KYGBgCgojIyMjICoqYykgU2Vjb25kIGxldmVsIHBhdGgqKgpgYGB7cn0KZGVzdF9wYXRoIDwtIGZpbGUucGF0aChkZXN0X3BhdGgsIHJhd19kYXRhKQoKaWYgKCFkaXIuZXhpc3RzKGRlc3RfcGF0aCkpIHsKICBkaXIuY3JlYXRlKGRlc3RfcGF0aCkgIyBjcmVhdGUgZGlyZWN0b3J5CiAgcHJpbnQocGFzdGUoIkZvbGRlciAiLCBkZXN0X3BhdGggLCAiY3JlYXRlZCBzdWNlc3NmdWxseSAiKSkKfSBlbHNlIHsKICBwcmludChwYXN0ZSgiRm9sZGVyICIsIGRlc3RfcGF0aCAsICJhbHJlYWR5IGV4aXN0cyIpKQp9CmBgYAoKIyMjIyAqKmQpIFNldCB3b3JraW5nIGRpcmVjdG9yeSoqCmBgYHtyfQpzZXR3ZChkZXN0X3BhdGgpCmBgYAoKIyMjIDEuMyBEb3dsb2FkIHNvdXJjZSBmaWxlcyB7LnRhYnNldH0KIyMjIyAqKmEpIFZhcmlhYmxlcyoqCmBgYHtyfQojIG1haW4gcGFnZSB3aXRoIHRoZSBzb3VyY2UgZGF0YQp0YXJnZXRfdXJsIDwtICJodHRwOi8vd3d3LnRzZS5qdXMuYnIvaG90c2l0ZXMvcGVzcXVpc2FzLWVsZWl0b3JhaXMvcHJlc3RhY2FvX2NvbnRhc19hbm9zLzIwMTguaHRtbCIKCiMgZ2V0IGh0bWwgZnJvbSBzb3VyY2UgVVJMIGFib3ZlCmh0bWwgICAgICAgPC0gIHJlYWRfaHRtbCh0YXJnZXRfdXJsKQoKIyB1c2UgY3NzIHNlbGVjdG9yIHRvIGp1c3QgZmlsdGVyIHRoZSBwYXRoIHdpdGggdGhlIG90aGVyIHVybCBhZHJlc3Nlcwpub2RlcyAgICAgIDwtICBodG1sX25vZGVzKGh0bWwsICdkaXYgcCBhJykKCiMgZmluYWwgZmV0Y2ggb2YgdGhlIHVybCBhZGRyZXNzZXMgd2l0aCB0aGUgcmF3IGRhdGEKemlwX3VybCAgICA8LSAgaHRtbF9hdHRyKG5vZGVzLCAnaHJlZicpCmBgYAoKIyMjIyAqKmIpIERvd25sb2FkIGZpbGVzKioKYGBge3J9CiMgbm93IG5lZWQgdG8gZG8gYSBmb3IgbG9vcCBpbiB0aGlzIGNhc2UKIyByIGhhbmRsZXMgdGhlIGRvd25sb2FkIG9mIHRoZSB3aG9sZSB2ZWN0b3IKIyAqKiogV0FSTklORyAqKioKIyBzb21lIGZpbGVzIGFyZSBodWdlIC0gPj0gMjAwIE1CCmRvd25sb2FkLmZpbGUodXJsID0gemlwX3VybCwgCiAgICAgICAgICAgICAgZGVzdGZpbGUgPSBmaWxlLnBhdGgoZGVzdF9wYXRoLCBiYXNlbmFtZSh6aXBfdXJsKSksCiAgICAgICAgICAgICAgbW9kZSA9ICd3YicpCmBgYAoKIyMjIyAqKmMpIFVuemlwaW5nKioKYGBge3J9Cgpmb3IgKGYgaW4gZmlsZS5wYXRoKGRlc3RfcGF0aCwgYmFzZW5hbWUoemlwX3VybCkpKSB7CiAgcHJpbnQoZikKICB1bnppcChmLCBleGRpciA9IGRlc3RfcGF0aCkKfQoKYGBgCgojIyMjICoqZCkgRGVsZXRlIHNvbWUgZmlsZXMqKgpgYGB7cn0KIyBkZWxldGUgcmVkdW5kYW50IGZpbGVzIHRoYXQgd2lsbCBub3QgYmUgdXNlZApwYXR0ZXJuICAgICAgICAgPC0gJypCUkFTSUwqJwpmaWxlc190b19yZW1vdmUgPC0gZ3JlcChkaXIoZGVzdF9wYXRoKSwgcGF0dGVybiA9IHBhdHRlcm4sIGludj1ULCB2YWx1ZSA9IFQpCmZpbGUucmVtb3ZlKGZpbGUucGF0aChkZXN0X3BhdGgsZmlsZXNfdG9fcmVtb3ZlKSkKYGBgCgoKIyMgKioyLiBMb2FkaW5nIGFuZCBjbGVhbmluZyB0aGUgZGF0YSoqCgojIyMgMi4xIExvYWQgYW5kIGNsZWFuIGRvd25sb2FkZWQgY3N2cyB7LnRhYnNldH0KIyMjIyAqKmEpIFJldmVudWVzKioKYGBge3J9CiMgcmVhZCByZXZlbnVlcyBjc3YKcmVjZWl0YSA8LSAgcmVhZC5jc3YoZmlsZS5wYXRoKGRlc3RfcGF0aCwgJ3JlY2VpdGFzX2NhbmRpZGF0b3NfMjAxOF9CUkFTSUwuY3N2JyksCiAgICAgICAgICAgICAgICAgICAgc2VwID0gJzsnLCAKICAgICAgICAgICAgICAgICAgICBkZWMgPSAnLCcsCiAgICAgICAgICAgICAgICAgICAgZW5jb2RpbmcgPSAnbGF0aW4xJykKCiMgd2UgaGF2ZSA1NyBjb2x1bW5zISAKIyB0byBrZWVwIHRoaW5ncyBzaW1wbGUgbGV0J3MgcmVtb3ZlIHRoZSBvbmVzIHdlIGtub3cgYXJlIG5vdCB1c2VmdWwgcmlnaHQgbm93CnJlY2VpdGEkU0dfVUYgICAgICAgICAgICAgICAgICAgICAgIDwtIE5VTEwKcmVjZWl0YSROUl9DUEZfVklDRV9DQU5ESURBVE8gICAgICAgPC0gTlVMTApyZWNlaXRhJENEX0VMRUlDQU8gICAgICAgICAgICAgICAgICA8LSBOVUxMCnJlY2VpdGEkRFNfRUxFSUNBTyAgICAgICAgICAgICAgICAgIDwtIE5VTEwKcmVjZWl0YSRDRF9USVBPX0VMRUlDQU8gICAgICAgICAgICAgPC0gTlVMTApyZWNlaXRhJE5NX1RJUE9fRUxFSUNBTyAgICAgICAgICAgICA8LSBOVUxMCnJlY2VpdGEkQU5PX0VMRUlDQU8gICAgICAgICAgICAgICAgIDwtIE5VTEwKcmVjZWl0YSREVF9HRVJBQ0FPICAgICAgICAgICAgICAgICAgPC0gTlVMTApyZWNlaXRhJEhIX0dFUkFDQU8gICAgICAgICAgICAgICAgICA8LSBOVUxMCnJlY2VpdGEkVFBfUFJFU1RBQ0FPX0NPTlRBUyAgICAgICAgIDwtIE5VTEwKcmVjZWl0YSREU19DQVJHT19DQU5ESURBVE9fRE9BRE9SICAgPC0gTlVMTApyZWNlaXRhJENEX0VTRkVSQV9QQVJUSURBUklBX0RPQURPUiA8LSBOVUxMCnJlY2VpdGEkRFNfRVNGRVJBX1BBUlRJREFSSUFfRE9BRE9SIDwtIE5VTEwKcmVjZWl0YSROTV9ET0FET1IgICAgICAgICAgICAgICAgICAgPC0gTlVMTApyZWNlaXRhJENEX01VTklDSVBJT19ET0FET1IgICAgICAgICA8LSBOVUxMCnJlY2VpdGEkTk1fTVVOSUNJUElPX0RPQURPUiAgICAgICAgIDwtIE5VTEwgICAgICAgIApyZWNlaXRhJFNRX0NBTkRJREFUT19ET0FET1IgICAgICAgICA8LSBOVUxMCnJlY2VpdGEkTlJfQ0FORElEQVRPX0RPQURPUiAgICAgICAgIDwtIE5VTEwKcmVjZWl0YSROUl9ET0NVTUVOVE9fRE9BQ0FPICAgICAgICAgPC0gTlVMTApyZWNlaXRhJFNRX1BSRVNUQURPUl9DT05UQVMgICAgICAgICA8LSBOVUxMCnJlY2VpdGEkU1FfUkVDRUlUQSAgICAgICAgICAgICAgICAgIDwtIE5VTEwKcmVjZWl0YSRDRF9DQVJHT19DQU5ESURBVE9fRE9BRE9SICAgPC0gTlVMTApyZWNlaXRhJE5SX0NQRl9DQU5ESURBVE8gICAgICAgICAgICA8LSBOVUxMCnJlY2VpdGEkTlJfQ1BGX0NOUEpfRE9BRE9SICAgICAgICAgIDwtIE5VTEwKcmVjZWl0YSROTV9QQVJUSURPICAgICAgICAgICAgICAgICAgPC0gTlVMTApyZWNlaXRhJE5SX1BBUlRJRE9fRE9BRE9SICAgICAgICAgICA8LSBOVUxMCnJlY2VpdGEkTk1fUEFSVElET19ET0FET1IgICAgICAgICAgIDwtIE5VTEwKcmVjZWl0YSROUl9QQVJUSURPICAgICAgICAgICAgICAgICAgPC0gTlVMTApyZWNlaXRhJENEX0ZPTlRFX1JFQ0VJVEEgICAgICAgICAgICA8LSBOVUxMCnJlY2VpdGEkQ0RfT1JJR0VNX1JFQ0VJVEEgICAgICAgICAgIDwtIE5VTEwKcmVjZWl0YSRDRF9OQVRVUkVaQV9SRUNFSVRBICAgICAgICAgPC0gTlVMTApyZWNlaXRhJENEX0VTUEVDSUVfUkVDRUlUQSAgICAgICAgICA8LSBOVUxMCnJlY2VpdGEkQ0RfQ05BRV9ET0FET1IgICAgICAgICAgICAgIDwtIE5VTEwKcmVjZWl0YSRTR19QQVJUSURPX0RPQURPUiAgICAgICAgICAgPC0gTlVMTAoKIyBmb3JtYXQgZGF0ZXMgdXNpbmcgbHVicmlkYXRlCnJlY2VpdGEkRFRfRUxFSUNBTyAgICAgICAgICAgIDwtIGRteShyZWNlaXRhJERUX0VMRUlDQU8pCnJlY2VpdGEkRFRfUFJFU1RBQ0FPX0NPTlRBUyAgIDwtIGRteShyZWNlaXRhJERUX1BSRVNUQUNBT19DT05UQVMpCnJlY2VpdGEkRFRfUkVDRUlUQSAgICAgICAgICAgIDwtIGRteShyZWNlaXRhJERUX1JFQ0VJVEEpCgojIGRpc3BsYXkgaGVhZApoZWFkKHJlY2VpdGEpCmBgYAoKIyMjIyAqKmIpIEV4cGVuc2VzIHBhaWQqKgpgYGB7cn0KIyBhbm90aGVyIHdheSB0byBkbyB0aGUgY2xlYW5zaW5nIGluIHIsIG5vdyB1c2luZyBleHBlbnNlcyBkYXRhCmRlc3Blc2EgPC0gIHJlYWQuY3N2KGZpbGUucGF0aChkZXN0X3BhdGgsICdkZXNwZXNhc19wYWdhc19jYW5kaWRhdG9zXzIwMThfQlJBU0lMLmNzdicpLAogICAgICAgICAgICAgICAgICAgIHNlcCA9ICc7JywgCiAgICAgICAgICAgICAgICAgICAgZGVjID0gJywnLAogICAgICAgICAgICAgICAgICAgIGVuY29kaW5nID0gJ2xhdGluMScpCgpybV9jb2x1bW5zIDwtIGMoJ05SX0NQRl9WSUNFX0NBTkRJREFUTycsJ1NHX1VGJywnQ0RfRUxFSUNBTycsJ0RTX0VMRUlDQU8nLAogICAgICAgICAgICAgICAgJ0NEX1RJUE9fRUxFSUNBTycsJ05NX1RJUE9fRUxFSUNBTycsJ0FOT19FTEVJQ0FPJywnRFRfR0VSQUNBTycsCiAgICAgICAgICAgICAgICAnSEhfR0VSQUNBTycsJ1RQX1BSRVNUQUNBT19DT05UQVMnLCdTUV9QUkVTVEFET1JfQ09OVEFTJywnTlJfQ1BGX0NBTkRJREFUTycsCiAgICAgICAgICAgICAgICAnTk1fUEFSVElETycsJ05SX1BBUlRJRE8nLCdEU19DTkFFX0ZPUk5FQ0VET1InLCdDRF9USVBPX0ZPUk5FQ0VET1InLCdDRF9DTkFFX0ZPUk5FQ0VET1InLAogICAgICAgICAgICAgICAgJ0RTX0VTRkVSQV9QQVJUX0ZPUk5FQ0VET1InLCdDRF9FU0ZFUkFfUEFSVF9GT1JORUNFRE9SJywnU0dfVUZfRk9STkVDRURPUicsCiAgICAgICAgICAgICAgICAnQ0RfTVVOSUNJUElPX0ZPUk5FQ0VET1InLCdOTV9NVU5JQ0lQSU9fRk9STkVDRURPUicsJ1NRX0NBTkRJREFUT19GT1JORUNFRE9SJywKICAgICAgICAgICAgICAgICdOUl9DQU5ESURBVE9fRk9STkVDRURPUicsJ0NEX0NBUkdPX0ZPUk5FQ0VET1InLCdEU19PUklHRU1fREVTUEVTQScsCiAgICAgICAgICAgICAgICAnQ0RfT1JJR0VNX0RFU1BFU0EnLCdTUV9QQVJDRUxBTUVOVE9fREVTUEVTQScpCgpkZXNwZXNhWywgcm1fY29sdW1uc10gPC1OVUxMCmhlYWQoZGVzcGVzYSkKYGBgCgojIyMjICoqYykgRXhwZW5zZXMgaGlyZWQqKgpgYGB7cn0KZGVzcGVzYV9jIDwtICByZWFkLmNzdihmaWxlLnBhdGgoZGVzdF9wYXRoLCAnZGVzcGVzYXNfY29udHJhdGFkYXNfY2FuZGlkYXRvc18yMDE4X0JSQVNJTC5jc3YnKSwKICAgICAgICAgICAgICAgICAgICBzZXAgPSAnOycsIAogICAgICAgICAgICAgICAgICAgIGRlYyA9ICcsJywKICAgICAgICAgICAgICAgICAgICBlbmNvZGluZyA9ICdsYXRpbjEnKQoKcm1fY29sdW1ucyA8LSBjKCdOUl9DUEZfVklDRV9DQU5ESURBVE8nLCdTR19VRicsJ0NEX0VMRUlDQU8nLCdEU19FTEVJQ0FPJywKICAgICAgICAgICAgICAgICdDRF9USVBPX0VMRUlDQU8nLCdOTV9USVBPX0VMRUlDQU8nLCdBTk9fRUxFSUNBTycsJ0RUX0dFUkFDQU8nLAogICAgICAgICAgICAgICAgJ0hIX0dFUkFDQU8nLCdUUF9QUkVTVEFDQU9fQ09OVEFTJywnU1FfUFJFU1RBRE9SX0NPTlRBUycsJ05SX0NQRl9DQU5ESURBVE8nLAogICAgICAgICAgICAgICAgJ05NX1BBUlRJRE8nLCdOUl9QQVJUSURPJywnRFNfQ05BRV9GT1JORUNFRE9SJywnQ0RfVElQT19GT1JORUNFRE9SJywnQ0RfQ05BRV9GT1JORUNFRE9SJywKICAgICAgICAgICAgICAgICdEU19FU0ZFUkFfUEFSVF9GT1JORUNFRE9SJywnQ0RfRVNGRVJBX1BBUlRfRk9STkVDRURPUicsJ1NHX1VGX0ZPUk5FQ0VET1InLAogICAgICAgICAgICAgICAgJ0NEX01VTklDSVBJT19GT1JORUNFRE9SJywnTk1fTVVOSUNJUElPX0ZPUk5FQ0VET1InLCdTUV9DQU5ESURBVE9fRk9STkVDRURPUicsCiAgICAgICAgICAgICAgICAnTlJfQ0FORElEQVRPX0ZPUk5FQ0VET1InLCdDRF9DQVJHT19GT1JORUNFRE9SJywnRFNfT1JJR0VNX0RFU1BFU0EnLAogICAgICAgICAgICAgICAgJ0NEX09SSUdFTV9ERVNQRVNBJywnU1FfUEFSQ0VMQU1FTlRPX0RFU1BFU0EnKQoKCmRlc3Blc2FfY1ssIHJtX2NvbHVtbnNdIDwtTlVMTApoZWFkKGRlc3Blc2FfYykKYGBgCgojIyMjICoqZCkgQmFja3VwIGNsZWFuIGZyYW1lcyoqCmBgYHtyfQpzYXZlUkRTKHJlY2VpdGEsICAgZmlsZS5wYXRoKGRlc3RfcGF0aCwgJ2NsZWFuX3JldmVudWUucmRzJykpCnNhdmVSRFMoZGVzcGVzYSwgICBmaWxlLnBhdGgoZGVzdF9wYXRoLCAnY2xlYW5fZXhwZW5zZXNfcGFpZC5yZHMnKSkKc2F2ZVJEUyhkZXNwZXNhX2MsIGZpbGUucGF0aChkZXN0X3BhdGgsICdjbGVhbl9leHBlbnNlc19oaXJlZC5yZHMnKSkKYGBgCgoKIyMjIDIuMiBEb3dubG9hZCBjYW5kaWRhdGUncyBhc3NldHMgZGF0YSB7LnRhYnNldH0KIyMjIyAqKmEpIERvd25sb2FkKioKYGBge3J9CmBgYAoKIyMjIyAqKmIpIENsZWFuKioKYGBge3J9CmBgYAoKIyMjIyAqKmMpIEJhY2t1cCoqCmBgYHtyfQoKYGBg